package com.hucheng.user.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.hucheng.common.page.PageParameter;
import com.hucheng.common.utils.TimeUtils;
import com.hucheng.user.entity.UserPointDO;
import com.hucheng.user.entity.UserPointDetailsDO;
import com.hucheng.user.entity.UserPointExpiredDetailsDO;
import com.hucheng.user.mapper.UserPointDetailsMapper;
import com.hucheng.user.mapper.UserPointExpiredDetailsMapper;
import com.hucheng.user.mapper.UserPointMapper;
import com.hucheng.user.service.UserPointService;
import com.hucheng.user.vo.UserPointVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * @Author: 凉白开不加冰
 * @Version: 0.0.1V
 * @Date: 2019-07-12
 * @Description: 用户积分
 **/
@Slf4j
@Component
@Service(interfaceClass = UserPointService.class, retries = -1, timeout = 5000)
public class UserPointServiceImpl implements UserPointService {

    @Autowired
    private UserPointExpiredDetailsMapper userPointExpiredDetailsMapper;

    @Autowired
    private UserPointMapper userPointMapper;

    @Autowired
    private UserPointDetailsMapper userPointDetailsMapper;

//    private ExecutorService service = Executors.newFixedThreadPool(10);

    ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("clean-point-%d").build();

    /**
     * corePoolSize int 核心线程池大小
     * maximumPoolSize int 最大线程池大小
     * keepAliveTime long 线程最大空闲时间
     * unit TimeUnit 时间单位
     * workQueue BlockingQueue<Runnable> 线程等待队列
     * threadFactory ThreadFactory 线程创建工厂
     * handler RejectedExecutionHandler 拒绝策略
     */
    private ExecutorService service = new ThreadPoolExecutor(5,
            10,
            10,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(),
            threadFactory,
            new ThreadPoolExecutor.AbortPolicy());

    @Override
    public UserPointVO getUserPoint(Integer userId) {
        //获取用户即将过期积分
        int expiredPoint = userPointExpiredDetailsMapper.getUserPointExpiredByUserId(userId);

        UserPointDO userPointDO = userPointMapper.get(userId);
        userPointDO.setBePointExpired(expiredPoint);

        return UserPointVO.buildUserPointVO(userPointDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addPoint(Integer point, String source, Integer userId) {
        log.info("新增积分开始 >>>>>>>> 用户 " + userId + " 来源 " + source + " 积分 " + point);
        //新增积分
        UserPointDO userPointDO = new UserPointDO();
        userPointDO.setPoint(point);
        userPointDO.setUserId(userId);
        userPointMapper.updateAddPointByUserId(userPointDO);
        //新增积分明细
        UserPointDetailsDO userPointDetailsDO = new UserPointDetailsDO();
        userPointDetailsDO.setIsDel(0);
        userPointDetailsDO.setPoint(point);
        userPointDetailsDO.setExpiredTime(TimeUtils.getDate(new Date(), 365));
        userPointDetailsDO.setPointType(1);
        userPointDetailsDO.setSource(source);
        userPointDetailsDO.setUserId(userId);
        userPointDetailsMapper.insert(userPointDetailsDO);
        //新增过期积分明细
        UserPointExpiredDetailsDO userPointExpiredDetailsDO = new UserPointExpiredDetailsDO();
        userPointExpiredDetailsDO.setPoint(point);
        userPointExpiredDetailsDO.setUserId(userId);
        userPointExpiredDetailsDO.setPointType(1);
        userPointExpiredDetailsDO.setSource(source);
        userPointExpiredDetailsDO.setExpiredTime(TimeUtils.getDate(new Date(), 365));
        userPointExpiredDetailsDO.setIsDel(0);
        userPointExpiredDetailsMapper.insert(userPointExpiredDetailsDO);
        log.info("新增积分结束 >>>>>>>> 用户 " + userId + " 来源 " + source + " 积分 " + point);
    }

    @Override
    public void cleanUserPointExpired() {
        //10 0 0 * * ? * 每天零点10秒执行
        service.execute(() -> {
            //每次找处理10条
            int pageSize = 5000;
            //当前处理数据
            final int[] curentSize = {1};
            int totalCount = userPointExpiredDetailsMapper.countByExpired();
            while (curentSize[0] <= totalCount) {
                PageParameter pageParameter = new PageParameter(curentSize[0], pageSize);
                List<UserPointExpiredDetailsDO> lists = userPointExpiredDetailsMapper.listByExpired(pageParameter);
                List<UserPointDO> pointDOList = new ArrayList<>();
                lists.forEach(userPointExpiredDetailsDO -> {
                    //修改过期表过期积分状态
                    userPointExpiredDetailsDO.setPointType(2);
                    //修改用户过期积分
                    UserPointDO userPointDO = new UserPointDO();
                    userPointDO.setUserId(userPointExpiredDetailsDO.getUserId());
                    userPointDO.setPointExpired(userPointExpiredDetailsDO.getPoint());
                    userPointDO.setPoint(userPointExpiredDetailsDO.getPoint());
                    pointDOList.add(userPointDO);
                    curentSize[0]++;
                });
                userPointMapper.updateBatchPoint(pointDOList);
                userPointExpiredDetailsMapper.updateBatchPointExpired(lists);
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            log.info("清除过期积分结束 >>>>>>>>> " + totalCount);
        });
    }
}
